home *** CD-ROM | disk | FTP | other *** search
/ Hyper Stacks 1994 May / Hyper Stacks (Pacific HiTech)(1994)[Mac].iso / HyperTalk / Turbo Pascal XCMD ƒ / XCMD.HowToUse < prev    next >
Encoding:
Text File  |  1988-08-31  |  10.6 KB  |  245 lines  |  [TEXT/TPAS]

  1. XCMD and XFCN: The Magic Hooks That Extend HyperTalk
  2.  
  3.     This documentation by Ted Kaehler, 1 August 1987
  4.     For HyperCard 1.0.  (Works with internal versions 1.0B9 and later.)
  5.     ©Apple Computer, Inc. 1987
  6.     All Rights Reserved.
  7.  
  8. [  Comments in brackets were written by Brian Liebowitz, and are specific
  9. to Turbo Pascal.  Information irrelevant to Turbo Pascal was deleted by 
  10. same]
  11.  
  12. Dan Winkler has created an interface that allows powerful new commands 
  13. to be added to HyperCard "in the field."  When a command in a script 
  14. cannot be found, HyperCard looks for a resource of type XCMD with 
  15. the same name as the unknown command.  Likewise, when a function cannot
  16. be found, HyperCard looks for a resource of type XFCN.  Consider XCMDs
  17. and XFCNs to be extensions of stack scripts.  Whenever a handler (for a 
  18. command or function) is not found in a stack script, HyperCard
  19. immediately looks for a XCMD or XFCN in that stack.  The total 
  20. inheritance order is: Button (or Field), Card, Stack, stack XCMD, Home,
  21. home XCMD, XCMD in HyperCard application file, HyperCard command.  An 
  22. XCMD or XFCN is a code resource with no header bytes (just like a desk 
  23. accessory).  You can move them from file to file with ResEdit or with 
  24. any other resource moving tool.
  25.  
  26. The only thing passed into an XCMD or XFCN is a pointer to a XCmdBlock.  
  27. It looks like this:
  28.  
  29.   XCmdPtr = ^XCmdBlock;
  30.   XCmdBlock =
  31.     RECORD
  32.       paramCount:  INTEGER;                  { the number of arguments }
  33.       params:      ARRAY[1..16] OF Handle;   { the arguments }
  34.       returnValue: Handle;                   { the result of this XCMD }
  35.       passFlag:    BOOLEAN;                  { pass the message on? }
  36.  
  37.       entryPoint:  ProcPtr;                  { call back to HyperCard }
  38.       request:     INTEGER;                  { what you want to do }
  39.       result:      INTEGER;                  { the answer it gives }
  40.       inArgs:      ARRAY[1..8] OF LongInt;   { args XCMD sends HyperCard }
  41.       outArgs:     ARRAY[1..4] OF LongInt;   { answer HyperCard sends back }
  42.     END;
  43.  
  44. You read the agruments (they are handles to zero terminated strings), 
  45. do whatever the purpose of this XCMD is, and optionally store a 
  46. result into returnValue.  All data values going to and from HyperTalk 
  47. are zero-terminated ASCII strings.
  48.  
  49. Resources of type XCMD are commands, and resourcs of type XFCN are 
  50. fuctions that return a value.  If you store a result string into 
  51. returnValue in a command, the user can get it by asking for "the result"
  52. (useful for explaining why there was an error).  In a function, you are
  53. expected to store the answer into returnValue.  If you don't store 
  54. anything, the result is the empty string.
  55.  
  56. If passFlag is false (the normal case), this XCMD or XFCN has handled the 
  57. message and the script resumes execution.  If passFlag is true, HyperCard
  58. searches the remaining inheritance chain for another handler or
  59. XCMD with the same name.  This is just like the "pass" control structure
  60. in a script.
  61.  
  62. The file Flash.p is an example XCMD.  It takes one argument which is 
  63. the ASCII characters for a decimal integer.  It inverts the screen 
  64. twice the number of times indicated.  It is meant to be used as a command 
  65. and puts an error string into "the result" if the argument is odd.
  66.  
  67. Peek.p is a function (XFCN) that returns the value of any memory location 
  68. in the machine (purists avert your eyes).
  69.  
  70.  
  71. The second part of the XCmdBlock record has to do with 
  72. calling HyperCard back in the middle of your code to ask a question.
  73. If you wanted to manage the call to HyperCard yourself, you would 
  74. fill inArgs with your arguments, put a request code in request,
  75. and JSR to the address in entryPoint.  HyperCard returns the values you
  76. requested in outArgs and a reslut code in result.
  77.   
  78. However, Dan Winkler has packaged the entire range of calls on HyperCard,
  79. so that if you are using Pascal, you can simply call a procedure.  Both 
  80. Peek and Flash use some conversion routines that Dan has kindly
  81. supplied.  The file XCmdGlue.inc has the glue procedures.  Handle is always
  82. a handle to a zero-terminated string.  If a handle is returned, you are
  83. responsible for disposing it.  The calls are:
  84.  
  85. PROCEDURE SendCardMessage(msg: Str255);
  86. {  Send a HyperCard message (a command with arguments) to the current 
  87. card. }
  88.  
  89. FUNCTION EvalExpr(expr: Str255): Handle;
  90. {  Evaluate a HyperCard expression and return the answer.  The answer is
  91.    a handle to a zero-terminated string. }
  92.  
  93. FUNCTION StringLength(strPtr: Ptr): LongInt;
  94. {  Count the characters from where strPtr points until the next zero byte. 
  95.    Does not count the zero itself.  strPtr must be a zero-terminated string.  }
  96.  
  97. FUNCTION StringMatch(pattern: Str255; target: Ptr): Ptr;
  98. { Perform case-insensitive match looking for pattern anywhere in
  99.   target, returning a pointer to first character of the first match,
  100.   in target or NIL if no match found.  pattern is a Pascal string,
  101.   and target is a zero-terminated string. }
  102.  
  103. PROCEDURE ZeroBytes(dstPtr: Ptr; longCount: LongInt);
  104. {  Write zeros into memory starting at destPtr and going for longCount 
  105.    number of bytes. }
  106.  
  107. FUNCTION PasToZero(str: Str255): Handle;
  108. {  Convert a Pascal string to a zero-terminated string.  Returns a handle
  109.    to a new zero-terminated string.  The caller must dispose the handle.
  110.    You'll need to do this for any result or argument you send from 
  111.    your XCMD to HyperTalk. }
  112.  
  113. PROCEDURE ZeroToPas(zeroStr: Ptr; VAR pasStr: Str255);
  114. {  Fill the Pascal string with the contents of the zero-terminated
  115.    string.  You create the Pascal string and pass it in as a VAR 
  116.    parameter.  Useful for converting the arguments of any XCMD to 
  117.    Pascal strings.}
  118.  
  119. FUNCTION StrToLong(str: Str31): LongInt;
  120. {  Convert a string of ASCII decimal digits to an unsigned long integer. }
  121.  
  122. FUNCTION StrToNum(str: Str31): LongInt;
  123. {  Convert a string of ASCII decimal digits to a signed long integer.
  124.    Negative sign is allowed.  }
  125.  
  126. FUNCTION StrToBool(str: Str31): BOOLEAN;
  127. {  Convert the Pascal strings 'true' and 'false' to booleans. }
  128.  
  129. FUNCTION StrToExt(str: Str31): Extended;
  130. {  Convert a string of ASCII decimal digits to an extended long integer. }
  131. VAR x: Extended;
  132.  
  133. FUNCTION LongToStr(posNum: LongInt): Str31;
  134. {  Convert an unsigned long integer to a Pascal string.  }
  135.  
  136. FUNCTION NumToStr(num: LongInt): Str31;
  137. {  Convert a signed long integer to a Pascal string.  }
  138.  
  139. FUNCTION NumToHex(num: LongInt; nDigits: INTEGER): Str31;
  140. {  Convert an unsigned long integer to a hexadecimal number and put it
  141.    into a Pascal string.  }
  142.  
  143. FUNCTION BoolToStr(bool: BOOLEAN): Str31;
  144. {  Convert a boolean to 'true' or 'false'.  }
  145. VAR str: Str31;
  146.  
  147. FUNCTION ExtToStr(num: Extended): Str31;
  148. {  Convert an extended long integer to decimal digits in a string.  }
  149.  
  150. FUNCTION GetGlobal(globName: Str255): Handle;
  151. {  Return a handle to a zero-terminated string containing the value of 
  152.    the specified HyperTalk global variable.  }
  153.  
  154. PROCEDURE SetGlobal(globName: Str255; globValue: Handle);
  155. {  Set the value of the specified HyperTalk global variable to be
  156.    the zero-terminated string in globValue.  The contents of the 
  157.    Handle are copied, so you must still dispose it afterwards.  }
  158.  
  159. FUNCTION GetFieldByName(cardFieldFlag: BOOLEAN; fieldName: Str255): 
  160. Handle;
  161. {  Return a handle to a zero-terminated string containing the value of 
  162.    field fieldName on the current card.  You must dispose the handle.  }
  163.  
  164. FUNCTION GetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum: INTEGER): 
  165. Handle;
  166. {  Return a handle to a zero-terminated string containing the value of 
  167.    field fieldNum on the current card.  You must dispose the handle.  }
  168.  
  169. FUNCTION GetFieldByID(cardFieldFlag: BOOLEAN; fieldID: INTEGER): Handle;
  170. {  Return a handle to a zero-terminated string containing the value of 
  171.    the field whise ID is fieldID.  You must dispose the handle.  }
  172.  
  173. PROCEDURE SetFieldByName(cardFieldFlag: BOOLEAN; fieldName: Str255; 
  174. fieldVal: Handle);
  175. {  Set the value of field fieldName to be the zero-terminated string 
  176.    in fieldVal.  The contents of the Handle are copied, so you must 
  177.    still dispose it afterwards.  }
  178.  
  179. PROCEDURE SetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum: INTEGER; 
  180. fieldVal: Handle);
  181. {  Set the value of field fieldNum to be the zero-terminated string 
  182.    in fieldVal.  The contents of the Handle are copied, so you must 
  183.    still dispose it afterwards.  }
  184.  
  185. PROCEDURE SetFieldByID(cardFieldFlag: BOOLEAN; fieldID: INTEGER; fieldVal: 
  186. Handle);
  187. {  Set the value of the field whose ID is fieldID to be the zero-
  188.    terminated string in fieldVal.  The contents of the Handle are 
  189.    copied, so you must still dispose it afterwards.  }
  190.  
  191. FUNCTION StringEqual(str1,str2: Str255): BOOLEAN;
  192. {  Return true if the two strings have the same characters.  
  193.    Case insensitive compare of the strings.  }
  194.  
  195. PROCEDURE ReturnToPas(zeroStr: Ptr; VAR pasStr: Str255);
  196. {  zeroStr points into a zero-terminated string.  Collect the 
  197.    characters from there to the next carriage Return and return 
  198.    them in the Pascal string pasStr.  If a Return is not found, 
  199.    collect chars until the end of the string. }
  200.  
  201. PROCEDURE ScanToReturn(VAR scanPtr: Ptr);
  202. {  Move the pointer scanPtr along a zero-terminated 
  203.    string until it points at a Return character
  204.    or a zero byte.  }
  205.  
  206. PROCEDURE ScanToZero(VAR scanPtr: Ptr);
  207. {  Move the pointer scanPtr along a zero-terminated 
  208.    string until it points at a zero byte.  }
  209.  
  210.  
  211.  
  212. Here are the files you will need:
  213.  
  214.  HyperXCmd.p
  215.  XCmdGlue.inc
  216.  Flash.p  (An example command to see how everything is really done.)
  217.  Peek.p   (An example function to see how everything is really done.)
  218.  
  219. [To compile an XCMD or XFCN in Turbo Pascal, simply include the compiler
  220. directive {$D PasXCMD} or {$DPasXFCN}, respectively.  You should also 
  221. remember to use the {$U-} directive, or else your XCMD or XFCN will crash.
  222. The XCMD or XFCN should be written as a procedure called PasXCMD or 
  223. PasXFCN, as the case may be. It accepts one parameter, (paramBlk:XCMDPtr).
  224. It should be included in a program whose name is the name of the XCMD.  
  225. The program should have an empty body (BEGIN END;).  See the examples
  226. included in this archive.
  227.  
  228. If you follow the templates included in this archive, the XCMD will be stored
  229. as a resource in a file whose name is the name of the XCMD.  In other words,
  230. the XCMD "Flash" will be store as XCMD "Flash", ID 300, in the file "Flash".
  231.  
  232. After compiling, use ResEdit to change the ID number to a unique value, so 
  233. that the new resource doesn't overwrite old ones.  Then copy the resource to
  234. the appropriate stack.]
  235.  
  236. Breakpoints do not appear to work in XCMDs, but putting a debugger call
  237. in your code does work.  In addition, saying:
  238.  
  239.    hd 'h'
  240.  
  241. in MacsBug allows you to find your resource in memory by seeing its name
  242. and location in the listing.
  243.  
  244. [Also, ProcPtrs don't seem to work correctly in XCMD's.]
  245.